using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.Office.Project.EPMSync.Config.Library;
using System.Collections.ObjectModel;
using Microsoft.Office.Project.EPMSync.Config.Editor.Properties;

namespace Microsoft.Office.Project.EPMSync.Config.Editor
{
    public partial class FormMapLookupValues : Form
    {
        private int _AttributeID;
        private Dictionary<int, string> _AttributeValues;
        private Dictionary<Guid, string> _LookupTableValues;
        private FormEditFieldMappings _ptrEditFieldMappings;

        public FormMapLookupValues(FormEditFieldMappings ptrEditFieldMappings)
        {
            InitializeComponent();
            _ptrEditFieldMappings = ptrEditFieldMappings;
        }

        #region Setup the Lists

        public bool SetLists(int attributeId,
            Dictionary<int, string> attributeValues,
            Dictionary<Guid, string> lookupTableValues,
            Collection<LookupMapEntry> lookupMap)
        {
            _AttributeID = attributeId;
            _AttributeValues = GetSortedAttributeValues(attributeValues);
            _LookupTableValues = GetSortedLookupValues(lookupTableValues);

            // TODO: should check if there are more custom fields than attributes
            //if (_AttributeValues.Count == _CustomFieldValues.Count)
            if (_AttributeValues.Count <= _LookupTableValues.Count)
            {
                // Add values already mapped, if there are any
                if (lookupMap != null)
                {
                    foreach (LookupMapEntry lme in lookupMap)
                    {
                        listBoxAttribute.Items.Add(_AttributeValues[lme.AttributeDefinitionId]);
                        listBoxLookupValues.Items.Add(_LookupTableValues[lme.PSLookupTableValueUid]);
                    }
                }

                // Add attribute values that haven't been mapped yet
                foreach (KeyValuePair<int, string> kvp in _AttributeValues)
                {
                    if (!ExistsInAttributeListBox(_AttributeValues[kvp.Key]))
                        listBoxAttribute.Items.Add(kvp.Value);
                }

                // Add lookup table values that haven't been mapped yet
                foreach (KeyValuePair<Guid, string> kvp in _LookupTableValues)
                {
                    if (!ExistsInLookupValueListBox(_LookupTableValues[kvp.Key]))
                        listBoxLookupValues.Items.Add(kvp.Value);
                }


            }
            else
            {
                this.Close();
                return false;
            }

            return true;
        }

        private static Dictionary<int, string> GetSortedAttributeValues(Dictionary<int, string> input)
        {
            SortedDictionary<string, int> sorted = new SortedDictionary<string, int>();
            Dictionary<int, string> rebuilt = new Dictionary<int, string>();

            foreach (KeyValuePair<int, string> kvp in input)
            {
                sorted.Add(kvp.Value, kvp.Key);
            }

            foreach (KeyValuePair<string, int> kvp in sorted)
            {
                rebuilt.Add(kvp.Value, kvp.Key);
            }

            return rebuilt;
        }

        private static Dictionary<Guid, string> GetSortedLookupValues(Dictionary<Guid, string> input)
        {
            SortedDictionary<string, Guid> sorted = new SortedDictionary<string, Guid>();
            Dictionary<Guid, string> rebuilt = new Dictionary<Guid, string>();

            foreach (KeyValuePair<Guid, string> kvp in input)
            {
                sorted.Add(kvp.Value, kvp.Key);
            }

            foreach (KeyValuePair<string, Guid> kvp in sorted)
            {
                rebuilt.Add(kvp.Value, kvp.Key);
            }

            return rebuilt;
        }

        private bool ExistsInAttributeListBox(string attributeName)
        {
            foreach (object item in listBoxAttribute.Items)
            {
                if (attributeName == item.ToString())
                    return true;
            }
            return false;
        }

        private bool ExistsInLookupValueListBox(string lookupValueName)
        {
            foreach (object item in listBoxLookupValues.Items)
            {
                if (lookupValueName == item.ToString())
                    return true;
            }
            return false;
        }

        #endregion

        #region Utility List Methods

        private int GetAttributeValueID(string attributeName)
        {
            foreach (KeyValuePair<int, string> kvp in _AttributeValues)
            {
                if (attributeName == kvp.Value)
                    return kvp.Key;
            }
            return 0;
        }

        private Guid GetLookupValueID(string lookupValueName)
        {
            foreach (KeyValuePair<Guid, string> kvp in _LookupTableValues)
            {
                if (lookupValueName == kvp.Value)
                    return kvp.Key;
            }
            return Guid.Empty;
        }
        #endregion

        #region Button Events

        private void buttonSave_Click(object sender, EventArgs e)
        {
            Dictionary<int, Guid> lookupValues = new Dictionary<int, Guid>();
            for (int i = 0; i <= listBoxAttribute.Items.Count - 1; i++)
            {
                lookupValues.Add(GetAttributeValueID(listBoxAttribute.Items[i].ToString()), GetLookupValueID(listBoxLookupValues.Items[i].ToString()));
            }

            _ptrEditFieldMappings.UpdateLookupValues(_AttributeID, lookupValues);

            this.Close();
        }

        private void buttonCancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void buttonUp_Click(object sender, EventArgs e)
        {
            if (listBoxLookupValues.SelectedItem != null)
            {
                int currentIndex = listBoxLookupValues.SelectedIndex;
                if (currentIndex > 0)
                {
                    string currentItem = listBoxLookupValues.SelectedItem.ToString();
                    listBoxLookupValues.Items.RemoveAt(currentIndex);
                    listBoxLookupValues.Items.Insert(currentIndex - 1, currentItem);
                    listBoxLookupValues.SelectedIndex = currentIndex - 1;
                }
            }

        }

        private void buttonDown_Click(object sender, EventArgs e)
        {
            if (listBoxLookupValues.SelectedItem != null)
            {
                int currentIndex = listBoxLookupValues.SelectedIndex;
                if (currentIndex < listBoxLookupValues.Items.Count - 1)
                {
                    string currentItem = listBoxLookupValues.SelectedItem.ToString();
                    listBoxLookupValues.Items.RemoveAt(currentIndex);
                    listBoxLookupValues.Items.Insert(currentIndex + 1, currentItem);
                    listBoxLookupValues.SelectedIndex = currentIndex + 1;
                }
            }
        }

        private void buttonDelete_Click(object sender, EventArgs e)
        {
            if (listBoxLookupValues.SelectedItem != null)
            {
                if (listBoxAttribute.Items.Count <= listBoxLookupValues.Items.Count - 1)
                {
                    int currentIndex = listBoxLookupValues.SelectedIndex;
                    listBoxLookupValues.Items.RemoveAt(listBoxLookupValues.SelectedIndex);
                    listBoxLookupValues.SelectedIndex = currentIndex - 1;
                }
                else
                    RightAwareMessageBox.Show(Resources.NoDeleteLookupValue, Resources.EditorTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

        #endregion

        private int indexOfItemUnderMouseToDrag;
        private int indexOfItemUnderMouseToDrop;

        private Rectangle dragBoxFromMouseDown;
        private Point screenOffset;

        private Cursor MyNoDropCursor;
        private Cursor MyNormalCursor;



        private void listBoxLookupValues_DragDrop(object sender, DragEventArgs e)
        {
            // Ensure that the list item index is contained in the data.
            if (e.Data.GetDataPresent(typeof(System.String)))
            {

                Object item = (object)e.Data.GetData(typeof(System.String));

                // Perform drag-and-drop, depending upon the effect.
                if (e.Effect == DragDropEffects.Copy ||
                    e.Effect == DragDropEffects.Move)
                {

                    // Insert the item.
                    if (indexOfItemUnderMouseToDrop != ListBox.NoMatches)
                        listBoxLookupValues.Items.Insert(indexOfItemUnderMouseToDrop, item);
                    else
                        listBoxLookupValues.Items.Add(item);

                }
            }
            //// Reset the label text.
            //DropLocationLabel.Text = "None";

        }

        //private void listBoxLookupValues_DragEnter(object sender, DragEventArgs e)
        //{
        //    // Reset the label text.
        //    DropLocationLabel.Text = "None";

        //}


        //private void listBoxLookupValues_DragLeave(object sender, EventArgs e)
        //{
        //    // Reset the label text.
        //    DropLocationLabel.Text = "None";
        //}


        private void listBoxLookupValues_MouseDown(object sender, MouseEventArgs e)
        {
            // Get the index of the item the mouse is below.
            indexOfItemUnderMouseToDrag = listBoxLookupValues.IndexFromPoint(e.X, e.Y);

            if (indexOfItemUnderMouseToDrag != ListBox.NoMatches)
            {

                // Remember the point where the mouse down occurred. The DragSize indicates
                // the size that the mouse can move before a drag event should be started.                
                Size dragSize = SystemInformation.DragSize;

                // Create a rectangle using the DragSize, with the mouse position being
                // at the center of the rectangle.
                dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
                                                               e.Y - (dragSize.Height / 2)), dragSize);
            }
            else
                // Reset the rectangle if the mouse is not over an item in the ListBox.
                dragBoxFromMouseDown = Rectangle.Empty;


        }

        private void listBoxLookupValues_MouseUp(object sender, MouseEventArgs e)
        {
            // Reset the drag rectangle when the mouse button is raised.
            dragBoxFromMouseDown = Rectangle.Empty;
        }

        private void listBoxLookupValues_MouseMove(object sender, MouseEventArgs e)
        {
            if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
            {

                // If the mouse moves outside the rectangle, start the drag.
                if (dragBoxFromMouseDown != Rectangle.Empty &&
                    !dragBoxFromMouseDown.Contains(e.X, e.Y))
                {

                    MyNormalCursor = Cursors.Arrow;
                    MyNoDropCursor = Cursors.UpArrow;


                    // The screenOffset is used to account for any desktop bands 
                    // that may be at the top or left side of the screen when 
                    // determining when to cancel the drag drop operation.
                    screenOffset = SystemInformation.WorkingArea.Location;

                    // Proceed with the drag-and-drop, passing in the list item.                    
                    DragDropEffects dropEffect = listBoxLookupValues.DoDragDrop(listBoxLookupValues.Items[indexOfItemUnderMouseToDrag], DragDropEffects.All | DragDropEffects.Link);

                    // If the drag operation was a move then remove the item.
                    if (dropEffect == DragDropEffects.Move)
                    {
                        listBoxLookupValues.Items.RemoveAt(indexOfItemUnderMouseToDrag);

                        // Selects the previous item in the list as long as the list has an item.
                        if (indexOfItemUnderMouseToDrag > 0)
                            listBoxLookupValues.SelectedIndex = indexOfItemUnderMouseToDrag - 1;

                        else if (listBoxLookupValues.Items.Count > 0)
                            // Selects the first item.
                            listBoxLookupValues.SelectedIndex = 0;
                    }

                    // Dispose of the cursors since they are no longer needed.
                    if (MyNormalCursor != null)
                        MyNormalCursor.Dispose();

                    if (MyNoDropCursor != null)
                        MyNoDropCursor.Dispose();
                }
            }

        }

        //private void listBoxLookupValues_GiveFeedback(object sender, GiveFeedbackEventArgs e)
        //{
        //    // Use custom cursors if the check box is checked.
        //    if (UseCustomCursorsCheck.Checked)
        //    {

        //        // Sets the custom cursor based upon the effect.
        //        e.UseDefaultCursors = false;
        //        if ((e.Effect & DragDropEffects.Move) == DragDropEffects.Move)
        //            Cursor.Current = MyNormalCursor;
        //        else
        //            Cursor.Current = MyNoDropCursor;

        //    }


        //}

        private void listBoxLookupValues_DragOver(object sender, DragEventArgs e)
        {
            // Determine whether string data exists in the drop data. If not, then
            // the drop effect reflects that the drop cannot occur.
            if (!e.Data.GetDataPresent(typeof(System.String)))
            {

                e.Effect = DragDropEffects.None;
                //DropLocationLabel.Text = "None - no string data.";
                return;
            }

            // Set the effect based upon the KeyState.
            if ((e.KeyState & (8 + 32)) == (8 + 32) &&
                (e.AllowedEffect & DragDropEffects.Link) == DragDropEffects.Link)
            {
                // KeyState 8 + 32 = CTL + ALT

                // Link drag-and-drop effect.
                e.Effect = DragDropEffects.Link;

            }
            else if ((e.KeyState & 32) == 32 &&
                (e.AllowedEffect & DragDropEffects.Link) == DragDropEffects.Link)
            {

                // ALT KeyState for link.
                e.Effect = DragDropEffects.Link;

            }
            else if ((e.KeyState & 4) == 4 &&
              (e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)
            {

                // SHIFT KeyState for move.
                e.Effect = DragDropEffects.Move;

            }
            else if ((e.KeyState & 8) == 8 &&
              (e.AllowedEffect & DragDropEffects.Copy) == DragDropEffects.Copy)
            {

                // CTL KeyState for copy.
                e.Effect = DragDropEffects.Copy;

            }
            else if ((e.AllowedEffect & DragDropEffects.Move) == DragDropEffects.Move)
            {

                // By default, the drop action should be move, if allowed.
                e.Effect = DragDropEffects.Move;

            }
            else
                e.Effect = DragDropEffects.None;

            // Get the index of the item the mouse is below. 

            // The mouse locations are relative to the screen, so they must be 
            // converted to client coordinates.

            indexOfItemUnderMouseToDrop =
                listBoxLookupValues.IndexFromPoint(listBoxLookupValues.PointToClient(new Point(e.X, e.Y)));

            //// Updates the label text.
            //if (indexOfItemUnderMouseToDrop != ListBox.NoMatches)
            //{

            //    DropLocationLabel.Text = "Drops before item #" + (indexOfItemUnderMouseToDrop + 1);
            //}
            //else
            //    DropLocationLabel.Text = "Drops at the end.";


        }

        private void listBoxLookupValues_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
        {
            // Cancel the drag if the mouse moves off the form.
            ListBox lb = sender as ListBox;

            if (lb != null)
            {

                Form f = lb.FindForm();

                // Cancel the drag if the mouse moves off the form. The screenOffset
                // takes into account any desktop bands that may be at the top or left
                // side of the screen.
                if (((Control.MousePosition.X - screenOffset.X) < f.DesktopBounds.Left) ||
                    ((Control.MousePosition.X - screenOffset.X) > f.DesktopBounds.Right) ||
                    ((Control.MousePosition.Y - screenOffset.Y) < f.DesktopBounds.Top) ||
                    ((Control.MousePosition.Y - screenOffset.Y) > f.DesktopBounds.Bottom))
                {

                    e.Action = DragAction.Cancel;
                }
            }

        }
    }
}